package com.lzm.toolfx.module.aio;

import com.lzm.toolfx.common.Property;
import com.lzm.toolfx.module.notiy.SocketObserver;
import com.lzm.toolfx.utils.DateUtil;
import javafx.application.Platform;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.AsynchronousChannelGroup;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.NotYetBoundException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


/*******************************************************************
 *                       AioServer Socket服务                       *
 *  PORT : Socket端口                                               *
 *  SocketObserver controller :  通知服务                           *
 *                                                                 *
 *  function:                                                      *
 *     ->start : 开启监听                                           *
 *     ->stop  : 停止监听                                           *
 *******************************************************************/

public class AioServer{
    private boolean run;
    private String host;
    private String PORT;
    private SocketObserver socketObserver;

    //线程池
    private ExecutorService executorService;
    //线程组
    private AsynchronousChannelGroup threadGroup;
    //服务器通道
    private AsynchronousServerSocketChannel socketChannel;

    private AioServer() {
        this.run = false;
        try {
            //NIO2.0  ~= Netty  Window > Linux  I/O  NIO ->JVM Java虚拟机实现 ——> AIO -> DMA
            // Linux IO ->AIO->DMA->CPU->内存  NIO——> JVM->开辟内存——>寄存器->CPU->内存
            // MAC
            executorService = Executors.newCachedThreadPool();
            threadGroup = AsynchronousChannelGroup.withCachedThreadPool(executorService, 1);
            socketChannel = AsynchronousServerSocketChannel.open(threadGroup);
        }catch (IOException e){
            //TODO Handle Exception
        }
    }

    public AioServer(String host, String port){
        this();
        try {
            //this.controller = observer;
            this.host = host;
            this.PORT = port;
            socketChannel.bind(new InetSocketAddress(host,Integer.parseInt(port)));
        } catch (IOException e ) {
            //e.printStackTrace();
        }
    }

    public AioServer(SocketObserver observer, String host, String port){
        this();
        try {
            this.socketObserver = observer;
            this.host = host;
            this.PORT = port;
            socketChannel.bind(new InetSocketAddress(host,Integer.parseInt(port)));
        } catch (IOException e ) {
            //e.printStackTrace();
        }
    }


    public void start() throws NotYetBoundException,InterruptedException{
        Platform.runLater(() -> {
            System.out.println(Property.dot+"\n"
                    + DateUtil.now() + "Server Started at Port:" + PORT
                    + "\n"+Property.dot);
        });
        //阻塞
        socketChannel.accept(this, new MsgHandler());
        run = true;
        //保持监听
        Thread.sleep(Integer.MAX_VALUE);
    }


    public void stop() {
        System.out.println(DateUtil.now()+"\tService stop");
        try {
            if(socketChannel.isOpen()) {
                socketChannel.close();
                threadGroup.shutdown();
                executorService.shutdown();
            }
        } catch (Exception e) {
            //Exception
        }
    }

    public boolean isRun() {
        return run;
    }

    public String getHost() {
        return host;
    }

    public String getPORT() {
        return PORT;
    }

    public SocketObserver getSocketObserver() {
        return socketObserver;
    }

    public ExecutorService getExecutorService() {
        return executorService;
    }

    public AsynchronousChannelGroup getThreadGroup() {
        return threadGroup;
    }

    public AsynchronousServerSocketChannel getSocketChannel() {
        return socketChannel;
    }

}
